from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
from exceptions.exception import ServiceException
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_stock.dao.basic_dao import BasicDao
from module_stock.entity.vo.basic_vo import DeleteBasicModel, BasicModel, BasicPageQueryModel
from utils.ak_util import filter_ak_stock
from utils.common_util import CamelCaseUtil
from utils.excel_util import ExcelUtil

import akshare as ak

class BasicService:
    """
    股票基础信息模块服务层
    """

    @classmethod
    async def get_basic_list_services(
        cls, query_db: AsyncSession, query_object: BasicPageQueryModel, is_page: bool = False
    ):
        """
        获取股票基础信息列表信息service

        :param query_db: orm对象
        :param query_object: 查询参数对象
        :param is_page: 是否开启分页
        :return: 股票基础信息列表信息对象
        """
        basic_list_result = await BasicDao.get_basic_list(query_db, query_object, is_page)

        return basic_list_result


    @classmethod
    async def add_basic_services(cls, query_db: AsyncSession, page_object: BasicModel):
        """
        新增股票基础信息信息service

        :param query_db: orm对象
        :param page_object: 新增股票基础信息对象
        :return: 新增股票基础信息校验结果
        """
        try:
            await BasicDao.add_basic_dao(query_db, page_object)
            await query_db.commit()
            return CrudResponseModel(is_success=True, message='新增成功')
        except Exception as e:
            await query_db.rollback()
            raise e

    @classmethod
    async def edit_basic_services(cls, query_db: AsyncSession, page_object: BasicModel):
        """
        编辑股票基础信息信息service

        :param query_db: orm对象
        :param page_object: 编辑股票基础信息对象
        :return: 编辑股票基础信息校验结果
        """
        edit_basic = page_object.model_dump(exclude_unset=True, exclude={})
        basic_info = await cls.basic_detail_services(query_db, page_object.symbol)
        if basic_info.symbol:
            try:
                await BasicDao.edit_basic_dao(query_db, edit_basic)
                await query_db.commit()
                return CrudResponseModel(is_success=True, message='更新成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='股票基础信息不存在')

    @classmethod
    async def delete_basic_services(cls, query_db: AsyncSession, page_object: DeleteBasicModel):
        """
        删除股票基础信息信息service

        :param query_db: orm对象
        :param page_object: 删除股票基础信息对象
        :return: 删除股票基础信息校验结果
        """
        if page_object.symbols:
            symbol_list = page_object.symbols.split(',')
            try:
                for symbol in symbol_list:
                    await BasicDao.delete_basic_dao(query_db, BasicModel(symbol=symbol))
                await query_db.commit()
                return CrudResponseModel(is_success=True, message='删除成功')
            except Exception as e:
                await query_db.rollback()
                raise e
        else:
            raise ServiceException(message='传入为空')

    @classmethod
    async def basic_detail_services(cls, query_db: AsyncSession, symbol: int):
        """
        获取股票基础信息详细信息service

        :param query_db: orm对象
        :param symbol: 
        :return: 对应的信息
        """
        basic = await BasicDao.get_basic_detail_by_id(query_db, symbol=symbol)
        if basic:
            result = BasicModel(**CamelCaseUtil.transform_result(basic))
        else:
            result = BasicModel(**dict())

        return result

    @staticmethod
    async def export_basic_list_services(basic_list: List):
        """
        导出股票基础信息信息service

        :param basic_list: 股票基础信息信息列表
        :return: 股票基础信息信息对应excel的二进制数据
        """
        # 创建一个映射字典，将英文键映射到中文键
        mapping_dict = {
            'symbol': '',
            'name': '',
        }
        binary_data = ExcelUtil.export_list2excel(basic_list, mapping_dict)

        return binary_data
    
    @classmethod
    async def sync_ak_services(cls, query_db: AsyncSession):
        """
        从akshare同步股票基础信息service
        1.从akshare获取股票列表数据
        2.查询股票基础信息表
        3
        3.1如果没有数据，说明是第一次同步，将akshare的数据直接插入数据库
        3.2如果有数据，则跟akshare的数据进行比对，进行增加、删除操作，说明akshare的增加了说明新股上市
        减少了说明是股票退市
        :param query_db: orm对象
        :return: 操作结果
        """
        try:
            datas_ak =  ak.stock_info_a_code_name()
            # 过滤主板股票
            datas_ak = filter_ak_stock(datas_ak, 'code', 'name')

            datas_ak = datas_ak[datas_ak['code'] ]
            symbol_list_ak =  datas_ak['code'].to_list()
            symbol_list_db = await BasicDao.get_all_symbols(query_db)

            if symbol_list_db and len(symbol_list_db) > 0 :
                #新增股票
                diff_symbols_ak = set(symbol_list_ak).difference(set(symbol_list_db))
                if diff_symbols_ak:
                    diff_datas_ak = datas_ak[datas_ak['code'].isin(diff_symbols_ak)]
                    diff_data_models = []
                    for diff_data in diff_datas_ak.itertuples():   
                        diff_data_models.append(BasicModel(symbol=diff_data.code, name=diff_data.name))
                    await BasicDao.batch_add_basic_dao(query_db, diff_data_models)
                #退市股票
                diff_symbols_db = set(symbol_list_db).difference(set(symbol_list_ak))
                if diff_symbols_db :
                    await BasicDao.batch_delete_basic_dao(query_db, diff_symbols_db)
            else:
                #没有数据，直接插入所有数据
                data_models = []
                for data_ak in datas_ak.itertuples():   
                    data_models.append(BasicModel(symbol=data_ak.code, name=data_ak.name))
                await BasicDao.batch_add_basic_dao(query_db, data_models)
            return CrudResponseModel(is_success=True, message='同步成功')
        except Exception as e:
            await query_db.rollback()
            raise e
